#pragma once
/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Sockets Connection Class
 *      Provides a TCP-based sockets client for performing sockets-oriented communications
 * originating from a connection accept()-ed by a Sockets daemon.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
#include "stdafx.h"
#include "ISocketConnection.h"
#include "SocketsIncludes.h"
#include "Win32Sockets.h"

using namespace System;
using namespace System::Runtime;
using namespace System::Runtime::InteropServices;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Threading;
using namespace Adaptive::Foundation;

namespace Adaptive
{
	namespace Network
	{
		namespace Sockets
		{
			/// <summary>
			/// Provides a TCP-based sockets client for performing sockets-oriented communications
			/// originating from a connection accept()-ed by a Sockets daemon.
			/// </summary>
			public ref class SocketsConnection : public DisposableObjectBase, ISocketConnection
			{
			public:
				/*--------------------------------------------------------------------------------
				 * Public Event Definitions
				 *------------------------------------------------------------------------------*/
				#pragma region Public Event Definitions
				/// <summary>
				/// Occurs when a network or TCP sockets error is encountered.
				/// </summary>
				event SocketErrorEventHandler^ SocketException;
				/// <summary>
				/// Occurs when data is recieved by the socket.
				/// </summary>
				event DataReceivedEventHandler^ DataReceived;
				/// <summary>
				/// Occurs when data is sent by the socket.
				/// </summary>
				event DataSentEventHandler^ DataSent;
				/// <summary>
				/// Occurs before data is sent by the socket.
				/// </summary>
				event EventHandler^ DataSending;
				/// <summary>
				/// Occurs when the connection is closed.
				/// </summary>
				event EventHandler^ Disconnected;
				/// <summary>
				/// Occurs once all initialization is done and the connection is ready for use.
				/// </summary>
				event EventHandler^ ConnectionEstablished;
				#pragma endregion

				/*--------------------------------------------------------------------------------
				 * Public Constructor / Dispose / Destructor Methods
				 *------------------------------------------------------------------------------*/
				#pragma region Public Constructor / Dispose / Destructor Methods
				/// <summary>
				/// Deallocates internally allocated objects.
				/// </summary>
				~SocketsConnection();
				/// <summary>
				/// Class destructor.
				/// </summary>
				!SocketsConnection();
				#pragma endregion

				/*--------------------------------------------------------------------------------
				 * Public Properties
				 *------------------------------------------------------------------------------*/
				#pragma region Public Properties
				/// <summary>
				/// Gets a value indicating whether the socket is connected to a remote host.
				/// </summary>
				/// <summary>
				/// <b>true</b> if a socket connection is established; otherwise, <b>false</b>.
				/// </summary>
				virtual property bool Connected{ bool get(); }
				/// <summary>
				/// Gets a value indicating whether pending, unread data is present in the buffer.
				/// </summary>
				/// <summary>
				/// <b>true</b> if data is present waiting to be read; otherwise, <b>false</b>.
				/// </summary>
				virtual property bool HasData{ bool get(); }
				/// <summary>
				/// Gets a unique ID for the socket connection instance.
				/// </summary>
				/// <summary>
				/// The underlying socket handle as a string.
				/// </summary>
				virtual property String^ Id { String^ get(); }
				#pragma endregion

				/*--------------------------------------------------------------------------------
				 * Public Methods / Functions
				 *------------------------------------------------------------------------------*/
				#pragma region Public Methods / Functions
				/// <summary>
				/// Closes the connection.
				/// </summary>
				virtual void Close();
				/// <summary>
				/// Reads a byte from the inbound data buffer.
				/// </summary>
				/// <returns>
				/// A byte value.
				/// </returns>
				virtual Byte ReadByte();
				/// <summary>
				/// Reads all pending data from tne inbound data buffer.
				/// </summary>
				/// <returns>
				/// A byte array containing the data that was read, or <b>null</b>
				/// if no data was read.
				/// </returns>
				virtual array<Byte>^ ReadAllBytes();
				/// <summary>
				/// Reads the specified number of bytes of pending data from tne inbound data buffer.
				/// </summary>
				/// <param name="numberOfBytes">The number of bytes to be read.</param>
				/// <returns>
				/// A byte array containing the data that was read, or <b>null</b>
				/// if no data was read.
				/// </returns>
				virtual array<Byte>^ ReadBytes(int numberOfBytes);
				/// <summary>
				/// Reads the inbound data buffer contents as a string.
				/// </summary>
				/// <returns>
				/// A string containing the buffer contents, or <see cref="String::Empty"/> if no data is present.
				/// </returns>
				virtual String^		ReadString();
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">A byte array containing the content to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int	Send(array<Byte>^ contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">A short integer to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int	Send(short contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">An integer to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int	Send(int contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">A long integer to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int	Send(__int64 contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">A character to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int	Send(char contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">An unsigned characer (or byte) t to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int	Send(unsigned char contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">A string containing the content to be sent.</param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int Send(String^ contentToSend);
				/// <summary>
				/// Sends data to a remote host.
				/// </summary>
				/// <param name="contentToSend">A string containing the content to be sent.</param>
				/// <param name="sendInAscii">
				/// A vlaue indicating whether to convert the Unicode string to a standard ASCII string.
				/// </param>
				/// <returns>The total number of bytes transmitted.</returns>
				virtual int Send(String^ contentToSend, bool sendInAscii);
				/// <summary>
				/// Waits for the specified data to appear in the buffer.
				/// </summary>
				/// <param name="dataToWaitFor">A byte array containing the data to wait for.</param>
				/// <param name="timeOutValue">
				/// The timeout value, in seconds.
				/// </param>
				/// <returns>The data that was read during the operation.</returns>
				virtual array<Byte>^	WaitForData(array<Byte>^ dataToWaitFor, int timeOutValue);
				/// <summary>
				/// Waits for the specified data to appear in the buffer.
				/// </summary>
				/// <param name="dataToWaitFor">A string containing the data to wait for.</param>
				/// <param name="timeOutValue">
				/// The timeout value, in seconds.
				/// </param>
				/// <returns>The data that was read during the operation.</returns>
				virtual String^			WaitForStringData(String^ dataToWaitFor, int timeOutValue);
				/// <summary>
				/// Sends the specified text and waits for the specified data to appear in the buffer.
				/// </summary>
				/// <remarks>
				/// This method is intended for use with text-based command-and-response protocols,
				/// such as SMTP, POP3, and FTP, among others.
				/// </remarks>
				/// <param name="dataToSend">Text content to be send to a remote host.</param>
				/// <param name="dataToWaitFor">A string containing the data to wait for.</param>
				/// <param name="timeOutValue">
				/// The timeout value, in seconds.
				/// </param>
				/// <returns>The data that was read during the operation.</returns>
				virtual String^			SendAndReceive(String^ dataToSend, String^ dataToWaitFor, int timeOutValue);
				#pragma endregion

			internal:
				/*--------------------------------------------------------------------------------
				 * Protected Constructor Methods
				 *------------------------------------------------------------------------------*/
				#pragma region Protected Constructor Methods
				/// <summary>
				/// Initializes a new instance of the class for the supplied socket handle.
				/// </summary>
				/// <param name="socketHandle">
				/// The unmanaged socket handle assigned by the system.
				/// </param>
				SocketsConnection(SOCKET socketHandle);
				/// <summary>
				/// Initializes a new instance of the class for the supplied socket handle.
				/// </summary>
				/// <param name="socketHandle">
				/// An <see cref="IntPtr"/> containing the unmanaged socket handle assigned by the system.
				/// </param>
				SocketsConnection(IntPtr socketHandle);
				/// <summary>
				/// Initializes a new instance of the class for the supplied socket handle.
				/// </summary>
				/// <param name="socketHandle">
				/// A <see cref="SafeSocketHandle"/> instance containing the unmanaged socket 
				/// handle assigned by the system.
				/// </param>
				SocketsConnection(SafeSocketHandle^ socketHandle);
				#pragma endregion

				protected:
				/*--------------------------------------------------------------------------------
				 * Event Methods
				 *------------------------------------------------------------------------------*/
				#pragma region Event Methods
				/// <summary>
				/// Raises the <see cref="SocketException"/> event.
				/// </summary>
				/// <param name="e">
				/// An <see cref="SocketErrorEventArgs"/> event arguments instance.
				/// </param>
				virtual void OnSocketException(SocketErrorEventArgs^ e);
				/// <summary>
				/// Raises the <see cref="DataReceived"/> event.
				/// </summary>
				/// <param name="e">
				/// An <see cref="DataReceivedEventArgs"/> event arguments instance.
				/// </param>
				virtual void OnDataReceived(DataReceivedEventArgs^ e);
				/// <summary>
				/// Raises the <see cref="DataSent"/> event.
				/// </summary>
				/// <param name="e">
				/// An <see cref="DataSentEventArgs"/> event arguments instance.
				/// </param>
				virtual void OnDataSent(DataSentEventArgs^ e);
				/// <summary>
				/// Raises the <see cref="DataSending"/> event.
				/// </summary>
				/// <param name="e">
				/// An <see cref="EventArgs"/> event arguments instance.
				/// </param>
				virtual void OnDataSending(EventArgs^ e);
				/// <summary>
				/// Raises the <see cref="Disconnected"/> event.
				/// </summary>
				/// <param name="e">
				/// An <see cref="EventArgs"/> event arguments instance.
				/// </param>
				virtual void OnDisconnected(EventArgs^ e);
				/// <summary>
				/// Raises the <see cref="ConnectionEstablished"/> event.
				/// </summary>
				/// <param name="e">
				/// An <see cref="EventArgs"/> event arguments instance.
				/// </param>
				virtual void OnConnectionEstablished(EventArgs^ e);
				#pragma endregion

				/*--------------------------------------------------------------------------------
				 * Protected Methods / Functions
				 *------------------------------------------------------------------------------*/
				#pragma region Protected Methods / Functions
				/// <summary>
				/// Modifies outbound data before it is transmitted.
				/// </summary>
				/// <remarks>
				/// This method may be overridden to perform any neccessary modifications (such as encryption) on the 
				/// data before it is transmitted.
				/// </remarks>
				/// <param name="originalData">
				/// The original data content as a byte array.
				/// </param>
				/// <returns>
				/// The byte array after transformation is applied.
				/// </returns>
				virtual array<Byte>^ TransformBeforeSend(array<Byte>^ originalData);
				/// <summary>
				/// Modifies inbound data after it is received.
				/// </summary>
				/// <remarks>
				/// This method may be overridden to perform any neccessary modifications (such as decryption) on the 
				/// data before it is returned to the caller.
				/// </remarks>
				/// <param name="originalData">
				/// The original data content read from the remote host as a byte array.
				/// </param>
				/// <returns>
				/// The byte array after transformation is applied.
				/// </returns>
				virtual array<Byte>^ TransformAfterReceive(array<Byte>^ originalData);
				#pragma endregion

			private:
				/*--------------------------------------------------------------------------------
				 * Private Member Declarations
				 *------------------------------------------------------------------------------*/
				#pragma region Private Member Declarations
				SafeSocketHandle^	_socketHandle;
				Thread^				_dataPollingThread;
				IPEndPoint^			_remoteEndPoint;
				IPEndPoint^			_localEndPoint;
				bool				_threadExecute;
				bool				_suspendThreadReading;
				LPCRITICAL_SECTION	_threadLock;
				#pragma endregion

				/*--------------------------------------------------------------------------------
				 * Private Methods / Functions
				 *------------------------------------------------------------------------------*/
				#pragma region Private Methods / Functions
				IPAddress^		ResolveHostName(String^ originalName);
				void			LaunchPollingThread();
				void			StopPollingThread();
				void			ExecutePollingThread();
				#pragma endregion


			};
		}
	}
}